package com.vegetable.modules.service.finance.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.common.utils.BankNoRedisService;
import com.vegetable.common.utils.R;
import com.vegetable.modules.entity.allocation.po.AllocationCollectionAddPO;
import com.vegetable.modules.entity.baseData.AddressBook;
import com.vegetable.modules.entity.baseData.BankCard;
import com.vegetable.modules.entity.baseData.FundAccount;
import com.vegetable.modules.entity.finance.BankFlowImportConfig;
import com.vegetable.modules.entity.finance.Transactions;
import com.vegetable.modules.entity.finance.po.FinancialCollectionAddPO;
import com.vegetable.modules.entity.finance.po.TransactionsQueryPO;
import com.vegetable.modules.entity.finance.po.TransactionsUpdatePO;
import com.vegetable.modules.entity.finance.vo.TradingFlowStatisticsVO;
import com.vegetable.modules.mapper.baseData.FundAccountMapper;
import com.vegetable.modules.mapper.finance.TransactionsMapper;
import com.vegetable.modules.service.allocation.IAllocationCollectionService;
import com.vegetable.modules.service.bank.convert.GeneralConverter;
import com.vegetable.modules.service.baseData.IAddressBookService;
import com.vegetable.modules.service.baseData.IBankCardService;
import com.vegetable.modules.service.finance.CustomBankFlowImportService;
import com.vegetable.modules.service.finance.IBankFlowImportConfigService;
import com.vegetable.modules.service.finance.IFinancialCollectionService;
import com.vegetable.modules.service.finance.ITransactionPaymentMatchService;
import com.vegetable.modules.service.finance.ITransactionsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class TransactionsServiceImpl extends ServiceImpl<TransactionsMapper, Transactions> implements ITransactionsService {
    @Resource
    private FundAccountMapper fundAccountMapper;
    @Resource
    private IAddressBookService addressBookService;
    
    @Autowired
    private IBankCardService bankCardService;
    
    @Autowired
    private IAllocationCollectionService allocationCollectionService;
    @Autowired
    private CustomBankFlowImportService customBankFlowImportService;
    @Resource
    private IBankFlowImportConfigService bankFlowImportConfigService;
    @Autowired
    private BankNoRedisService bankNoRedisService;
    
    @Autowired
    private ITransactionPaymentMatchService transactionPaymentMatchService;

    @Override
    @Transactional
    public R saveBatch(MultipartFile file, Long accountId) throws Exception {
        FundAccount fa = fundAccountMapper.selectById(accountId);
        if(Objects.isNull(fa)){
            throw new RuntimeException("账户不存在，请确认后重试.");
        }
        
        List<Transactions> transactions = new ArrayList<>();
        
        // 检查是否存在自定义导入配置
        boolean useCustomConfig = hasCustomImportConfig(fa.getAccountType());
        
        if (useCustomConfig) {
            try {
                // 优先尝试使用自定义字段映射配置导入
                transactions = customBankFlowImportService.parseBankFlowFile(file, getBankTypeByAccountType(fa.getAccountType()));
            } catch (Exception e) {
                log.warn("使用自定义字段映射配置导入失败，回退到原有导入方式: {}", e.getMessage());
                // 如果自定义导入失败，则使用原有导入方式
                GeneralConverter generalConverter = new GeneralConverter();
                transactions = parseWithGeneralConverter(generalConverter, fa, file);
            }
        } else {
            // 使用原有导入方式
            GeneralConverter generalConverter = new GeneralConverter();
            transactions = parseWithGeneralConverter(generalConverter, fa, file);
        }
        
        // 处理包含*的bankNo
        processBankNoWithAsterisk(transactions);
        
        List<Transactions> ttList = transactions;
//        for(Transactions tt : transactions){
//            if(StrUtil.isNotBlank(tt.getBankNo()) && tt.getBankNo().contains("****") ){
//                log.info("{}的银行卡号{}包含违禁词，无法判断是否重复，所以这条数据要删除", tt, tt.getBankNo());
//                continue;
//            }else{
//                ttList.add(tt);
//            }
//        }
        if(CollectionUtil.isEmpty(ttList)){
            return R.fail("导入失败，请联系技术人员");
        }
        for(Transactions t : ttList){
            t.setFundAccountId(fa.getId());
            t.setFundAccountName(fa.getAccountName());
            // 设置
            t.setUniqueMark(Transactions.generateUniqueFlowId(t));
        }
        int res = saveBatch1(ttList);
        return R.success("导入成功" + res + "数据");
    }

    /**
     * 处理包含*的bankNo
     * @param transactions 交易列表
     */
    private void processBankNoWithAsterisk(List<Transactions> transactions) {
        for (Transactions t : transactions) {
            String bankNo = t.getBankNo();
            if (StrUtil.isNotBlank(bankNo) && bankNo.contains("*")) {
                log.info("旧的银行卡号{}", bankNo);
                String newBankNo = bankNo.replace("****", "%");
                log.info("新的银行卡号{}", newBankNo);
                QueryWrapper<Transactions> qWrapper = new QueryWrapper<>();
                qWrapper.apply("bank_no like '" + newBankNo + "'");
                qWrapper.notIn("bank_no", Arrays.asList(bankNo));
                List<Transactions> qList = baseMapper.selectList(qWrapper);
                if(!CollectionUtil.isEmpty(qList)){
                    t.setBankNo(qList.get(0).getBankNo());
                    log.info("把原先的银行卡号{}替换成{}", bankNo, qList.get(0).getBankNo());
                }
            }
        }
    }

    /**
     * 判断是否需要使用自定义导入配置
     * @param accountType 账户类型
     * @return 是否使用自定义配置
     */
    private boolean hasCustomImportConfig(Integer accountType) {
        String bankType = getBankTypeByAccountType(accountType);
        // 这里可以查询数据库判断是否存在自定义配置
        // 简单起见，我们假设所有银行都支持自定义配置
        BankFlowImportConfig config = bankFlowImportConfigService.getByBankType(bankType);
        return Objects.nonNull(config);
    }

    /**
     * 根据账户类型获取银行类型
     * @param accountType 账户类型
     * @return 银行类型
     */
    private String getBankTypeByAccountType(Integer accountType) {
        switch (accountType) {
            case 1: return "WECHAT"; // 微信
            case 2: return "ALIPAY"; // 支付宝
            case 3: return "BOC"; // 中国银行
            case 4: return "CCB"; // 建设银行
            case 5: return "ABC"; // 农业银行
            case 6: return "ICBC"; // 工商银行
            case 7: return "WFBC"; // 潍坊银行
            case 8: return "SCRCU"; // 农村信用社
            case 9: return "PSBC"; // 邮政银行
            default: return "OTHER";
        }
    }

    /**
     * 使用通用转换器解析文件
     * @param generalConverter 通用转换器
     * @param fa 资金账户
     * @param file 文件
     * @return 银行流水列表
     * @throws Exception 异常
     */
    private List<Transactions> parseWithGeneralConverter(GeneralConverter generalConverter, FundAccount fa, MultipartFile file) throws Exception {
        List<Transactions> transactions = new ArrayList<>();
        switch (fa.getAccountType()){
            case 0:
                // 现金，不可能有这种选择
                break;
            case 1:
                // 微信
                transactions = generalConverter.parse("beehive-wx", "beehive-wx", file);
                break;
            case 2:
                // 支付宝
                transactions = generalConverter.parse("beehive-ali", "beehive-ali", file);
                break;
            case 3:
                transactions = generalConverter.parse("beehive-boc", "beehive-boc", file);
                // 中国银行
                break;
            case 4:
                // 建设银行
                transactions = generalConverter.parse("beehive-ccb", "beehive-ccb", file);
                break;
            case 5:
                // 农业银行
                transactions = generalConverter.parse("beehive-abc", "beehive-abc", file);
                break;
            case 6:
                // 工商银行
                transactions = generalConverter.parse("beehive-icbc", "beehive-icbc", file);
                break;
            case 7:
                // 潍坊银行
                transactions = generalConverter.parse("beehive-wfbc", "beehive-wfbc", file);
                break;
            case 8:
                // 农村信用社
                transactions = generalConverter.parse("beehive-scrcu", "beehive-scrcu", file);
                break;
            case 9:
                // 邮政银行
                transactions = generalConverter.parse("beehive-psbc", "beehive-psbc", file);
                break;
            default:
                break;
        }
        return transactions;
    }

    @Override
    public int saveBatch1(List<Transactions> transFlows) throws Exception {
        Transactions fastOne = transFlows.get(0);
        int effectRow = this.baseMapper.insertIgnoreBatch(transFlows);
        if(effectRow > 0){
            // 最近的一次流水
            Transactions newEst = lastT(fastOne.getFundAccountId());
            // 更新账号剩余金额
            FundAccount fa = new FundAccount();
            fa.setId(fastOne.getFundAccountId());
            fa.setTotalBalance(newEst.getBalanceAmount());
            fa.setUpdateTime(new Date());
            fundAccountMapper.updateById(fa);
            Transactions.sortByTradingTimeDesc(transFlows); // 执行倒序排序
        }
        List<String> uniqueMarks = transFlows.stream().map(el -> el.getUniqueMark()).collect(Collectors.toList());
        List<Transactions> exists = selectByUnitMarks(uniqueMarks);
        for( Transactions trans : exists){
            if ("WECHAT".equals(trans.getChannel())){
                continue;
            }
            if ("ALIPAY".equals(trans.getChannel())){
                continue;
            }
            // 尝试关联该流水的系统账号
            List<BankCard> bankCardList = bankCardService.selectByBankNo(trans.getBankNo());
            BankCard bankCard;
            if(CollectionUtil.isEmpty(bankCardList) || (CollectionUtil.isNotEmpty(bankCardList) && bankCardList.size() > 1)){
                log.info("{}银行卡号找不到匹配项或者有多个匹配项，无法自动匹配", trans.getBankNo());
                continue;
            }else{
                bankCard = bankCardList.get(0);
                trans.setAbId(bankCard.getAddressBookId());
                // 获取通讯录信息以获取名称
                AddressBook addressBook = addressBookService.queryById(bankCard.getAddressBookId());
                if (addressBook != null) {
                    trans.setAbName(addressBook.getNoteName());
                }
            }
            if("INCOME".equals(trans.getTradingType())){
                // 如果是收入的流水，则尝试跟回款关联
                AllocationCollectionAddPO po = new AllocationCollectionAddPO();
                po.setCustomerId(bankCard.getAddressBookId());
                // 获取通讯录信息以获取名称
                AddressBook addressBook = addressBookService.queryById(bankCard.getAddressBookId());
                if (addressBook != null) {
                    po.setCustomerName(addressBook.getNoteName());
                }
                po.setAccountId(trans.getFundAccountId());
                po.setAccountName(trans.getFundAccountName());
                po.setTotalAmount(trans.getTradingAmount());
                po.setTradingTime(trans.getTradingTime());
                po.setBankName(trans.getBankName());
                po.setBankNo(trans.getBankNo());
                po.setTransactionId(trans.getId());
                allocationCollectionService.saveAllocationCollection(po);
            }
        }
        return effectRow;
    }

    @Override
    public IPage<Transactions> queryList(TransactionsQueryPO po) {
        Page<Transactions> page = new Page<>(po.getPage(), po.getLimit());
        QueryWrapper<Transactions> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(po.getFundAccountId()), "fund_account_id", po.getFundAccountId());
        queryWrapper.like(StrUtil.isNotBlank(po.getCounterparty()), "counterparty", po.getCounterparty());
        queryWrapper.like(StrUtil.isNotBlank(po.getTradingDescription()), "trading_description", po.getTradingDescription());
        queryWrapper.eq(Objects.nonNull(po.getTradingAmount()), "trading_amount", po.getTradingAmount());
        queryWrapper.eq(StrUtil.isNotBlank(po.getTradingType()), "trading_type", po.getTradingType());
        queryWrapper.eq(StrUtil.isNotBlank(po.getBankNo()), "bank_no", po.getBankNo());
        queryWrapper.eq(Objects.nonNull(po.getAbId()), "ab_id", po.getAbId());
        queryWrapper.like(StrUtil.isNotBlank(po.getRemark()), "remark", po.getRemark());
        // 根据是否已处理过滤：已处理 ab_id != 0，未处理 ab_id == 0
        if (Objects.nonNull(po.getIsProcessed())) {
            if (po.getIsProcessed()) {
                // 已处理：ab_id != 0
                queryWrapper.ne("ab_id", 0);
            } else {
                // 未处理：ab_id == 0
                queryWrapper.eq("ab_id", 0);
            }
        }
        if(ObjectUtil.isNotNull(po.getStartTime())){
            queryWrapper.gt( "trading_time", DateUtil.beginOfDay(po.getStartTime()));
        }
        if(ObjectUtil.isNotNull(po.getEndTime())){
            queryWrapper.lt( "trading_time", DateUtil.endOfDay(po.getEndTime()));
        }
        queryWrapper.orderByDesc("trading_time");
        IPage<Transactions> result = baseMapper.selectPage(page, queryWrapper);
        return result;
    }

    @Override
    public IPage<Transactions> queryListByAdId(Long adId, Integer page, Integer limit) {
        Page<Transactions> pageObj = new Page<>(page, limit);
        QueryWrapper<Transactions> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ab_id", adId);
        queryWrapper.eq("trading_type", "EXPENSE");
        queryWrapper.apply("matched_amount < trading_amount");
        queryWrapper.orderByDesc("trading_time");
        return baseMapper.selectPage(pageObj, queryWrapper);
    }

    @Override
    public List<TradingFlowStatisticsVO> statisticsFlow(TransactionsQueryPO po) {
        List<TradingFlowStatisticsVO> res = baseMapper.statisticsFlow(po);
        return res;
    }

    @Override
    @Transactional
    public Integer updateFlowBelong(TransactionsUpdatePO po) throws Exception {
        Integer effectRow = 0;
        Transactions exist = baseMapper.selectById(po.getId());
        if(ObjectUtil.isNull(exist)){
            log.error("需要修改的流水信息不存在：{}", JSONObject.toJSONString(po));
            throw new RuntimeException("需要修改的流水信息不存在");
        }
//        if(ObjectUtil.isNotNull(exist.getAbId()) &&  exist.getAbId() != 0){
//            log.error("流水已经分配完毕：{}", JSONObject.toJSONString(po));
//            throw new RuntimeException("流水已经分配完毕，请勿重复操作");
//        }
        AddressBook ab = addressBookService.queryById(po.getAbId());
        if(ObjectUtil.isNull(ab)){
            log.error("账户信息不存在：{}", JSONObject.toJSONString(po));
            throw new RuntimeException("账户信息不存在");
        }
        
        // 检查目标用户是否已有该银行卡信息，如果没有则自动新增
        // 如果银行卡号是空或者包含*号则跳过
        if (StrUtil.isNotBlank(exist.getBankNo()) && !exist.getBankNo().contains("*")) {
            List<BankCard> bankCards = bankCardService.listByAddressBookId(po.getAbId());
            boolean hasBankCard = bankCards.stream().anyMatch(card -> 
                StrUtil.isNotBlank(card.getBankNo()) && card.getBankNo().equals(exist.getBankNo()));
            
            // 如果没有该银行卡信息，则自动新增
            if (!hasBankCard) {
                BankCard newBankCard = new BankCard();
                newBankCard.setAddressBookId(po.getAbId());
                newBankCard.setBankNo(exist.getBankNo());
                newBankCard.setBankName(exist.getBankName());
                newBankCard.setAccountName(exist.getCounterparty());
                newBankCard.setStatus(1);
                newBankCard.setIsDefault(0);
                newBankCard.setIsDel(0);
                bankCardService.save(newBankCard);
            }
        }
        
        if(po.getEffectAllFlow() && StrUtil.isNotBlank(exist.getBankNo())){
            // 如果true 则把符合卡号的流水全部归属于该ab
            Transactions updater = new Transactions();
            updater.setAbId(po.getAbId());
            updater.setAbName(ab.getNoteName());
            QueryWrapper<Transactions> wrapper = new QueryWrapper<>();
            wrapper.eq("bank_no", exist.getBankNo());
            // 添加超时控制，限制更新条数
            wrapper.last("limit 1000"); // 限制一次最多更新1000条记录
            effectRow = baseMapper.update(updater, wrapper);
            List<Transactions> effects = baseMapper.selectList(wrapper);
            if(CollectionUtil.isNotEmpty(effects)){
                for(Transactions effect : effects){
                    saveAllocationCollection(effect, ab);
                }
            }
        }else{
            // 更新流水的归属id
            Transactions updater = new Transactions();
            BeanUtils.copyProperties(po, updater);
            updater.setAbName(ab.getNoteName());
            effectRow = baseMapper.updateById(updater);
            saveAllocationCollection(exist, ab);
        }

        // 当交易流水的 ab_id 对应到某个代办时，自动将该流水与对应的代办付款记录进行匹配
//        try {
//            Transactions updatedTransaction = baseMapper.selectById(po.getId());
//            transactionPaymentMatchService.autoMatchTransactionToPayment(updatedTransaction);
//        } catch (Exception e) {
//            log.warn("自动匹配交易流水与付款记录时出现异常: {}", e.getMessage());
//            // 不抛出异常，避免影响主流程
//        }
        
        return effectRow;
    }

    private void saveAllocationCollection(Transactions exist, AddressBook ab) throws Exception {
        if("INCOME".equals(exist.getTradingType())){
            // 如果是收入的流水，则尝试跟回款关联
            AllocationCollectionAddPO saver = new AllocationCollectionAddPO();
            saver.setCustomerId(ab.getId());
            saver.setCustomerName(ab.getNoteName());
            saver.setAccountId(exist.getFundAccountId());
            saver.setAccountName(exist.getFundAccountName());
            saver.setTotalAmount(exist.getTradingAmount());
            saver.setTradingTime(exist.getTradingTime());
            saver.setBankName(exist.getBankName());
            saver.setBankNo(exist.getBankNo());
            saver.setTransactionId(exist.getId());
            allocationCollectionService.saveAllocationCollection(saver);
        }
    }

    private Transactions lastT (Long fundAccountId){
        QueryWrapper<Transactions> wrapper = new QueryWrapper<>();
        wrapper.eq("fund_account_id", fundAccountId);
        wrapper.orderByDesc("trading_time");
        wrapper.last("limit 1");
        return baseMapper.selectOne(wrapper);
    }

    private List<Transactions> selectByUnitMarks(List<String> uniqueMarks){
        QueryWrapper<Transactions> wrapper = new QueryWrapper<>();
        wrapper.in("unique_mark", uniqueMarks);
        return baseMapper.selectList(wrapper);
    };
}